ユーザーポリシーを使用したS3バケットへのアクセスコントロールを公式チュートリアルで理解する
はじめに
皆さんこんにちは。石橋です。今回は、Amazon S3(以下S3)のユーザーベースのアクセス制御を理解するために、公式ドキュメント内のチュートリアルを行いましたので、その様子を書いていきます。
今回実装するアクセス制御
デフォルトではS3の全てのリソースはプライベートであり、そのリソースを作成したAWSアカウントだけがリソースにアクセスできます。リソースの所有者は、アクセスポリシーを作成することにより、他のユーザーにアクセス許可を付与することができます。S3で提供されているアクセスポリシーオプションは、以下の3つに分類されます。
- ユーザーボリシー
- バケットポリシー
- ACL
今回はこの内のユーザーポリシーを実装していきます。 今回実装するアクセス制御は以下のようになります。
- Privateなどの階層とその下に1,2つのオブジェクトを持つS3バケット(companybucket)。
- IAMグループ(Consultants)に属する2人のIAMユーザー(AliceとBob)
- IAMグループアタッチするユーザー共有のIAMポリシー
- IAMユーザーに直接アタッチするユーザー固有のインラインポリシー
このような実装により、開発担当のAliceはDevelopmentの階層のオブジェクトに対してのみ読み書き可能で、経理担当のBobはFinanceの階層のオブジェクトに対してのみ読み書き可能といったアクセス管理を実装します。
実装
ステップ1:バケットを作成する
検証用のバケットを作成します。チュートリアルでは"companybucket"という名前のバケットを作成していましたが、S3のバケット名は全世界で一意である必要があるので、今回私は"companybucket-cm-ishibashi"としました。ご自身で異なるバケット名で実装される場合は、以後のバケット名を指定する箇所を適宜読み替えるようにしてください。
バケットの下に3つのフォルダを作成し、各フォルダの下に1つか2つドキュメントをアップロードします。今回私は、チュートリアルの形にのっとり、以下のようにファイルをアップロードしました。
- Private/privDoc1.txt
- Private/privDoc2.zip
- Development/project1.xls
- Development/project2.xls
- Finance/Tax2011/document1.pdf
- Finance/Tax2011/document2.pdf
- s3-dg.pdf
ステップ2:IAMユーザーとグループを作成する
今回ユーザーポリシーを付与するユーザーとグループを作成します。今回は2人のIAMユーザー(AliceとBob)とIAMグループ(Consultants)を作成し、2人のIAMユーザー(AliceとBob)をIAMグループ(consultants)に追加します。 IAMユーザーの作成に関する詳細な手順はこちらを、IAMグループの作成に関する詳細な手順はこちらを参考にしてください。
ステップ3:IAM ユーザーにアクセス許可が付与されていないことを確認する
作成したIAMユーザーでコンソールにログインし、S3コンソールに移動します。 ユーザーにアクセス許可が付与されていないため、アクセス拒否のメッセージが表示されることを確認します。
ステップ4:グループレベルのアクセス許可を付与する
ユーザーがS3に対する操作を実行できるように、アクセス許可を付与するポリシーを作成し、Consultantsグループにアタッチします。
ステップ4-1:全てのバケットのリストを表示するアクセス許可を付与する。
ルートユーザーでコンソールにサインインし、IAMコンソール左ペインの「ポリシー」から「ポリシーの作成」を選択。 JSONタブを選択し、以下を貼り付けます。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowGroupToSeeBucketListInTheConsole", "Action": ["s3:ListAllMyBuckets"], "Effect": "Allow", "Resource": ["arn:aws:s3:::*"] } ] }
Actionはアクセスの種類を指定しており、ポリシーの"s3:ListAllMyBuckets"は定義済みのS3アクションです。このアクションはAmazon S3 GETサービスオペレーションを対象とし、認証された送信者が所有するすべてのバケットのリストを返します。Effect要素の値は、特定のアクセスを許可するかどうかを決定しており、ここではAllow(許可)を指定しています。
「ポリシーの確認」を選択します。次のページで「名前」フィールドに「AllowGroupToSeeBucketListInTheConsole」と入力し、「ポリシーの作成」をクリックします。
作成した「AllowGroupToSeeBucketListInTheConsole」をConsultantsグループにアタッチします。 管理ポリシーをアタッチする詳細な手順については、こちらを参照してください。
アクセス許可のテストします。IAMユーザー(AliceかBob)でコンソールにサインインし、バケットが表示されることを確認します。
しかし現状だとバケットは表示されますが、バケット内のオブジェクトは表示されません。
ステップ4-2:バケットのルートレベルの内容をユーザーが表示できるようにする
次に、Consuletantsグループのすべてのユーザーがルートレベルのバケット項目を一覧表示できるようにします。
ルートルーザーでAWSコンソールにログインし、Consultantsグループにアタッチされている、既存のAllowGroupToSeeBucketListInTheConsoleのポリシーを以下のように書き換えます。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowGroupToSeeBucketListAndAlsoAllowGetBucketLocationRequiredForListBucket", "Action": [ "s3:ListAllMyBuckets", "s3:GetBucketLocation" ], "Effect": "Allow", "Resource": [ "arn:aws:s3:::*" ] }, { "Sid": "AllowRootLevelListingOfCompanyBucket", "Action": ["s3:ListBucket"], "Effect": "Allow", "Resource": ["arn:aws:s3:::companybucket-cm-ishibashi"], "Condition":{ "StringEquals":{ "s3:prefix":[""], "s3:delimiter":["/"] } } } ] }
このポリシードキュメントを理解するには、コンソールでバケットを選択した時にS3に送信されるリクエスト、レスポンスを把握する必要があります。 バケット名を選択すると、コンソールからS3にGET Bucket(List Objects)リクエストが送信されます。 このリクエストには、prefixパラメータとdelimiterパラメータが含まれています。prefixパラメータには、S3オブジェクトのprefixを指定し、delimiterパラメーターには、S3バケットにおける論理的な階層を示す区切り文字である"/"が指定されています。 つまりここでは、prefixが""であるルートの階層のリソースへの閲覧権限を付与していることがわかります。
このアクセス許可では、ルートの下の階層(Development/以下など)のリソースは表示されません。
ステップ5:IAMユーザーAliceに特定のアクセス許可を付与する
現在の状況では、IAMユーザーであるAliceとBobに対して以下のような権限が付与されています。
- 親アカウントが所有するうすべてのバケットを表示する
- companybucket-cm-ishibashiバケット内のルートレベルの項目を表示する
ここからはユーザー固有のアクセス許可を付与します。
ステップ5-1:IAMユーザーAliceにDevelopmentフォルダの内容を表示するアクセス許可を付与する
ルートユーザーで、マネジメントコンソールにログインし、IAMコンソール左ペインの「ユーザー」からAliceを選択します。 「インラインポリシーの追加」からJSONタブを選択し、以下のポリシードキュメントを貼り付けます。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowListBucketIfSpecificPrefixIsIncludedInRequest", "Action": ["s3:ListBucket"], "Effect": "Allow", "Resource": ["arn:aws:s3:::companybucket-cm-ishibashi"], "Condition":{ "StringLike":{"s3:prefix":["Development/*"] } } } ] }
「ポリシーの確認」を選択し、次にページで「名前」フィールドに名前を入力し、「ポリシーの作成」を選択します。今回はAllowListBucketIfSpecificPrefixIsIncludedInRequestという名前でポリシーを作成しました。
Aliceでマネジメントコンソールにログインして、S3コンソールからバケットのDevelopment以下の項目が閲覧可能であることを確認します。
ステップ5-2:IAMユーザーAliceにDevelopmentフォルダ内のオブジェクトを読み書きするアクセス許可を付与する
現段階だと、AliceはDevelopment以下の項目は表示できても、そのオブジェクトに対して読み書きをすることはできません。 Aliceにこの権限を付与するには、アタッチしたインラインポリシーを以下のように書き換えます。
{ "Version": "2012-10-17", "Statement":[ { "Sid":"AllowListBucketIfSpecificPrefixIsIncludedInRequest", "Action":["s3:ListBucket"], "Effect":"Allow", "Resource":["arn:aws:s3:::companybucket-cm-ishibashi"], "Condition":{ "StringLike":{"s3:prefix":["Development/*"] } } }, { "Sid":"AllowUserToReadWriteObjectDataInDevelopmentFolder", "Action":["s3:GetObject", "s3:PutObject"], "Effect":"Allow", "Resource":["arn:aws:s3:::companybucket-cm-ishibashi/Development/*"] } ] }
更新されたポリシーをテストするために、IAMコンソールにAliceでログインして、バケットのDevelopment以下のオブジェクトがダウンロードできることを確認します。
ステップ5-3:バケットの他のフォルダに対するIAMユーザーAliceのアクセス許可を明示的に拒否する
現在IAMユーザーAliceに許可されている権限は以下の通りです。
- companybucket-cm-ishibashiバケットのルートレベルの内容を表示することができる
- Developmentフォルダのオブジェクトを読み書きすることができる
これに加え、厳密にアクセス許可を制限したい場合は、バケットの他のフォルダへのAliceのアクセスを明示的に拒否することができます。 以下のようにAliceにアタッチされているインラインポリシーを書き換えます。
{ "Version": "2012-10-17", "Statement":[ { "Sid":"AllowListBucketIfSpecificPrefixIsIncludedInRequest", "Action":["s3:ListBucket"], "Effect":"Allow", "Resource":["arn:aws:s3:::companybucket-cm-ishibashi"], "Condition":{ "StringLike":{"s3:prefix":["Development/*"] } } }, { "Sid":"AllowUserToReadWriteObjectDataInDevelopmentFolder", "Action":["s3:GetObject", "s3:PutObject"], "Effect":"Allow", "Resource":["arn:aws:s3:::companybucket-cm-ishibashi/Development/*"] }, { "Sid": "ExplicitlyDenyAnyRequestsForAllOtherFoldersExceptDevelopment", "Action": ["s3:ListBucket"], "Effect": "Deny", "Resource": ["arn:aws:s3:::companybucket-cm-ishibashi"], "Condition":{ "StringNotLike": {"s3:prefix":["Development/*",""] }, "Null" : {"s3:prefix":false } } } ] }
Conditionブロックには2つの条件式があり、これらの条件式の結果はANDを使用して結合されます。つまり、両方の条件がtrueの場合、結合された条件の結果はtureです。ここでは結果がtrueになった場合に、明示的に拒否のアクションが適用されます。 つまりここでは、
- Null条件により、prefixがnullでリクエストされたときに条件はfalseとなる。
- つまり、"prefixがnull"="ルート"の項目は表示。
- StringNotLike条件により、prefixが"Development/*"の時以外は、trueとなる。
となり、「prefixがnullでなく、"Development/*"の時以外は、s3:ListBuceketのActionを明示的に拒否(Deny)となっています。 これにより、Development以外の階層であるFinanceなどの階層で項目が表示されないようになります。
ステップ6:IAMユーザーBobに特定のアクセス許可を付与する
Aliceのときと同様にBobにもアクセス許可を付与します。Bobの場合はFinanceフォルダの読み込み・書き込みを許可して、それ以外の階層の項目の表示を明示的に拒否します。 このような設定の場合、Bobに以下のようなインラインポリシーをアタッチすれば、アクセスを管理することができます。
{ "Version": "2012-10-17", "Statement":[ { "Sid":"AllowListBucketIfSpecificPrefixIsIncludedInRequest", "Action":["s3:ListBucket"], "Effect":"Allow", "Resource":["arn:aws:s3:::companybucket-cm-ishibashi"], "Condition":{ "StringLike":{"s3:prefix":["Finance/*"] } } }, { "Sid":"AllowUserToReadWriteObjectDataInDevelopmentFolder", "Action":["s3:GetObject", "s3:PutObject"], "Effect":"Allow", "Resource":["arn:aws:s3:::companybucket-cm-ishibashi/Finance/*"] }, { "Sid": "ExplicitlyDenyAnyRequestsForAllOtherFoldersExceptDevelopment", "Action": ["s3:ListBucket"], "Effect": "Deny", "Resource": ["arn:aws:s3:::companybucket-cm-ishibashi"], "Condition":{ "StringNotLike": {"s3:prefix":["Finance/*",""] }, "Null" : {"s3:prefix":false } } } ] }
内容としては、Aliceのときと同じで、DevelopmentがFinanceに変更されてるだけです。 Bobでマネジメントコンソールにログインして更新を確認します。
ステップ7:Privateフォルダをセキュリティで保護する
今回は、どのユーザーもPrivateフォルダの内容にアクセスできないように、このフォルダへのアクセスを明示的に拒否するポリシーを追加します。 ルートユーザーでマネジメントコンソールにログインして、IAMグループConsultantsにアタッチされているAllowGroupToSeeBucketListInTheConsoleのポリシーを以下のように書き換えます。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowGroupToSeeBucketListAndAlsoAllowGetBucketLocationRequiredForListBucket", "Action": ["s3:ListAllMyBuckets", "s3:GetBucketLocation"], "Effect": "Allow", "Resource": ["arn:aws:s3:::*"] }, { "Sid": "AllowRootLevelListingOfCompanyBucket", "Action": ["s3:ListBucket"], "Effect": "Allow", "Resource": ["arn:aws:s3:::companybucket-cm-ishibashi"], "Condition":{ "StringEquals":{"s3:prefix":[""]} } }, { "Sid": "RequireFolderStyleList", "Action": ["s3:ListBucket"], "Effect": "Deny", "Resource": ["arn:aws:s3:::*"], "Condition":{ "StringNotEquals":{"s3:delimiter":"/"} } }, { "Sid": "ExplictDenyAccessToPrivateFolderToEveryoneInTheGroup", "Action": ["s3:*"], "Effect": "Deny", "Resource":["arn:aws:s3:::companybucket-cm-ishibashi/Private/*"] }, { "Sid": "DenyListBucketOnPrivateFolder", "Action": ["s3:ListBucket"], "Effect": "Deny", "Resource": ["arn:aws:s3:::*"], "Condition":{ "StringLike":{"s3:prefix":["Private/"]} } } ] }
追記されている部分で - "Private/*"への全てのActionの明示的拒否 - "Private/"のprefixを持つAction(s3:ListBucket)の明示的拒否 が指定されています。 これにより、IAMグループConsultantsに属するIAMユーザーは、Privateの階層の項目の表示や、オブジェクトへのあらゆる操作ができなくなります。
Aliceでマネジメントコンソールにログインして、Privateの階層の項目が表示されないことを確認します。
ステップ8:クリーンナップ
IAMユーザーAliceとBobを削除します。詳細な手順については、IAM ユーザーガイド のIAM ユーザーの削除を参照してください。 S3バケットを削除します。
まとめ
今回のチュートリアルで、S3のユーザーベースのアクセス権限を実装しながら学ぶことができました。IAMポリシードキュメントで、バケットやその階層に対する操作や、その許可・拒否などを実際にどのように記載するかを理解することができました。実際にこのように階層でプロジェクトが分離されており、ユーザーごとに権限を分離したいケースは結構あると思いますので、そのときはこのようなユーザーベースのアクセス管理で実装してみてはいかがでしょうか。
この記事が誰かの参考になれば幸いです。